#include <nuttx/config.h>

#include <stdio.h>
#include <fcntl.h>
#include <sched.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>

#include <wchar.h>
#include <syslog.h>
#include "gpsutils/minmea.h"

#include <time.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <nuttx/ioexpander/gpio.h>




#define MINI_FRAME_SIZE     (11)
#define XYDM_FRAMR_START    (0xAA11)          
#define XYDM_FRAMR_STOP     (0x1A1D)
    
    
#pragma pack(1)
typedef struct{
    uint16_t start;
    uint8_t sn;
    uint16_t len;
    uint8_t type;
    uint8_t code;
    uint8_t *context;
    uint16_t crc;
    uint16_t stop;
}xy_frame_t;
#pragma pack()


typedef union{
    uint8_t value;
    struct{
        uint8_t type: 5;
        uint8_t qos: 3;
    }qos;
}qos_u;

typedef struct{
    uint8_t number[6];
    qos_u qos;
    uint8_t len;
    uint8_t *content;
}xydm_content_t;


typedef union{
    uint32_t value;
    float fvalue;
}uint32_float_t;


typedef struct{
    uint16_t year;
    uint8_t month;
    uint8_t day;
}xydm_date_t;


typedef struct{
    uint8_t hours;
    uint8_t minitues;
    uint8_t seconds;
}xydm_time_t;


typedef struct{
    uint8_t batterylvl;
    uint32_float_t height;
    uint32_float_t lonti;
    uint32_float_t lati;
    xydm_date_t date;
    xydm_time_t time;
}xydm_dtu_info_t;


typedef struct{
    uint16_t sat_num;
    uint16_t est_time;
}xydm_ovoertop_t;


typedef struct{
    uint8_t number[6];
    qos_u qos;
    uint8_t length;
    uint8_t content[200];
}xydm_uplink_ctx_t;


typedef struct{
    struct{
        xydm_date_t date;
        xydm_time_t time;
    }start;
    struct{
        xydm_date_t date;
        xydm_time_t time;
    }stop;    
}xydm_sat_ovtop_time_t;

enum{
    MSG_TYPE_NONE                           = 0x00,
    MSG_TYPE_PARAM_SET                      = 0x01, /* param sets */
    MSG_TYPE_STATUS_CHECK                   = 0x02, /* status check */
    MSG_TYPE_INTERACTION                    = 0x03, /* interaction data */
    MSG_TYPE_EPHEMERIS                      = 0x04, /* ephemeris data */
};

/* param sets CODE */
enum{
    MSG_CODE_SET_REQ_BAUD                   = 0x00,
};

enum{
    MSG_CODE_SET_RSP_BAUD                   = 0x01,
};


/* status check CODE */
enum{
    MSG_CODE_CHECK_REQ_MODULE_ACTIVE        = 0x00,
    MSG_CODE_CHECK_REQ_USER_NUMBER          = 0x02,
    MSG_CODE_CHECK_REQ_UPLINK_RATE          = 0x04,
    MSG_CODE_CHECK_REQ_SW_VERSION           = 0x06,
    MSG_CODE_CHECK_REQ_OVERTOP_TIME         = 0x08,
    MSG_CODE_CHECK_REQ_COMMUNICATION        = 0x0A,
    MSG_CODE_CHECK_REQ_REGISTER_OVERTOP     = 0x0F,
    MSG_CODE_CHECK_RSP_TEIMINAL_STATUS      = 0x0E,
};

enum{
    MSG_CODE_CHECK_RSP_MODULE_ACTIVE        = 0x01,
    MSG_CODE_CHECK_RSP_USER_NUMBER          = 0x03,
    MSG_CODE_CHECK_RSP_UPLINK_RATE          = 0x05,
    MSG_CODE_CHECK_RSP_SW_VERSION           = 0x07,
    MSG_CODE_CHECK_RSP_OVERTOP_TIME         = 0x09,
    MSG_CODE_CHECK_RSP_COMMUNICATION        = 0x0B,
    MSG_CODE_CHECK_RSP_COMM_RESULT          = 0x0C,
    MSG_CODE_CHECK_REQ_TERMINAL_STATUS      = 0x0D,
};


/* interaction data */
enum{
    MSG_CODE_INTERACTION_REQ_UPLINK             = 0x00,
};

enum{
    MSG_CODE_INTERACTION_RSP_DOWNLINK           = 0x01,
};


/* ephemeris data */
enum{
    MSG_CODE_EPHEMERIS_REQ_INPUT                = 0x00,
};

enum{
    MSG_CODE_EPHEMERIS_RSP_INPUT                = 0x01,
};

#define CONFIG_XYDM_DEVPATH    ("/dev/ttyS2")

volatile uint8_t g_u8Count = 0;
uint8_t g_u8Txbuffer[255];
uint8_t g_u8Rxbuffer[255];
uint8_t g_u8Poweron = 0;
uint8_t g_u8Id[6];
int fd;
int gpfd;
enum gpio_pintype_e pintype;
bool invalue;
bool outvalue = false;
xydm_sat_ovtop_time_t next;
uint8_t overtop_cnt = 0;
uint8_t uplink_cnt = 0;
static bool g_xydm_daemon_started;
//static bool g_gps_daemon_started;

static volatile bool gpssyned = false;
static volatile bool gpslocated = false;
struct minmea_sentence_rmc rmcframe;
struct minmea_sentence_gga ggaframe;

static uint16_t crc16(uint8_t* pData, int length);
int xydm_inquire_usrid(void);

int xydm_wakeup_pin_init(void)
{
	int ret = -1;
	gpfd = open("/dev/gpout0", O_RDWR);
	if(gpfd < 0){
      int errcode = errno;
      fprintf(stderr, "ERROR: Failed to open %s: %d\r\n", "/dev/gpout0", errcode);
      return -1;	
	}
	
  /* Get the pin type */

  ret = ioctl(gpfd, GPIOC_PINTYPE, (unsigned long)((uintptr_t)&pintype));
  if (ret < 0)
    {
      int errcode = errno;
      fprintf(stderr, "ERROR: Failed to read pintype from %s: %d\r\n", "/dev/gpout0", errcode);
      close(gpfd);
      return -1;
    }
	
	if(GPIO_OUTPUT_PIN != pintype){
		printf("xydm wakeup pin should be set to output type[%s]. \r\n",(pintype ==GPIO_INPUT_PIN)?"input":"interrupt");
		return -1;
	}
    	
	return 0;
}

int xydm_module_set_wakeup_pin(bool state)
{
  int ret;
  /* Read the pin value */
  /* Read the pin value */
  outvalue = true;
  ret = ioctl(gpfd, GPIOC_READ, (unsigned long)((uintptr_t)&invalue));
  if (ret < 0)
    {
      int errcode = errno;
      fprintf(stderr, "ERROR: Failed to read value from %s: %d\r\n", "/dev/gpout0", errcode);
      close(gpfd);
      return -1;
    }

  printf("  Output pin:    Value=%u\r\n", (unsigned int)invalue);
  printf("  Writing:       Value=%u\r\n", (unsigned int)outvalue);

  /* Write the pin value */

  ret = ioctl(gpfd, GPIOC_WRITE, (unsigned long)outvalue);
  if (ret < 0)
   {
     int errcode = errno;
     fprintf(stderr, "ERROR: Failed to write value %u from %s: %d\r\n",
             "/dev/gpout0", (unsigned int)outvalue, errcode);
     close(gpfd);
     return -1;
   }

  /* Re-read the pin value */

  ret = ioctl(gpfd, GPIOC_READ, (unsigned long)((uintptr_t)&invalue));
  if (ret < 0)
    {
      int errcode = errno;
      fprintf(stderr, "ERROR: Failed to re-read value from %s: %d\r\n",
              "/dev/gpout0", errcode);
      close(gpfd);
      return -1;
    }

  printf("  Verify:        Value=%u\r\n", (unsigned int)invalue);

  return 0;
}


void xydm_module_wakeup(void)
{
	if(0 > xydm_module_set_wakeup_pin(true)){
		printf("xydm module wakeup failed .\r\n");
	}else{
		printf("xydm module wakeup .\r\n");
	}
}


void xydm_module_sleep(void)
{
	if(0 > xydm_module_set_wakeup_pin(false)){
		printf("xydm module sleep failed .\r\n");
	}else{
		printf("xydm module sleep .\r\n");
	}
}


int xydm_gps_time_get(uint32_t *utc, int year,int month, int day, int hour, int min, int sec) {
    struct tm x;
    time_t y;

    if (utc != NULL) {
        memset(&x, 0, sizeof(x));
        if (year < 100) { /* 2-digits year, 20xx */
            x.tm_year = year + 100; /* 100 years offset to 1900 */
        } else { /* 4-digits year, Gregorian calendar */
            x.tm_year = year - 1900;
        }
        x.tm_mon = month - 1; /* tm_mon is [0,11], month is [1,12] */
        x.tm_mday = day;
        x.tm_hour = hour;
        x.tm_min = min;
        x.tm_sec = sec;
        y = mktime(&x) ;//- timezone; /* need to substract timezone bc mktime assumes time vector is local time */
        if (y == (time_t)(-1)) {
            printf("ERROR: FAILED TO CONVERT BROKEN-DOWN TIME\r\n");
            return -1;
        }
        
        *utc = y;
    }
    return 0;
}




void xydm_init(void)
{
   // int ret;
   
    if(0 > xydm_wakeup_pin_init()){
    	printf("xydm wakeup pin init failed .\r\n");
    }
   
    //xydm_module_wakeup();
    printf("open %s .\r\n", CONFIG_XYDM_DEVPATH);
    fd = open(CONFIG_XYDM_DEVPATH, O_RDWR | O_NONBLOCK);
    if (fd < 0){
        printf("Unable to open file %s\n",CONFIG_XYDM_DEVPATH);
    }
    /* update usr status */
#if 0    
    ret = xydm_inquire_usrid();
    if(ret < 0){
        printf("inquire user number error.\r\n");
    }else if(ret > 0){
        printf("inquire user number message error.\r\n");
    }
    printf("inquired user id : ");
    for(uint8_t i=0; i < 6; i++){
      printf("%02x", g_u8Id[i]);  
    }
    printf("\r\n");
#endif    
}

int xydm_frame_format(xy_frame_t *pframe, uint8_t *buffer, uint8_t len)
{
    uint8_t *pbuf;
    
    if((pframe == NULL) || (buffer == NULL) || (len < MINI_FRAME_SIZE))
        return -1;
    
    if((pframe->len < 5) || (len < pframe->len + 6)){
        printf("foramt length error :%d.\r\n", pframe->len);
        return -1;
    }
    
    *buffer++ = (uint8_t)(pframe->start >> 8);
    *buffer++ = (uint8_t)pframe->start ;
    pbuf = buffer;
    *buffer++ = pframe->sn;
    *buffer++ = (uint8_t)(pframe->len >> 8);
    *buffer++ = (uint8_t)(pframe->len >> 0);
    *buffer++ = pframe->type;
    *buffer++ = pframe->code;
    memcpy(buffer, pframe->context, pframe->len - 5);
    buffer += pframe->len - 5;
    pframe->crc = crc16(pbuf, pframe->len);
    *buffer++ = (uint8_t)(pframe->crc >> 8);
    *buffer++ = (uint8_t)(pframe->crc >> 0);
    *buffer++ = (uint8_t)(pframe->stop >> 8);
    *buffer++ = (uint8_t)(pframe->stop >> 0);    
    
    return (pframe->len + 6);
}

int xydm_frame_make(xy_frame_t *pframe, uint8_t *buffer, uint8_t length, uint8_t type, uint8_t code)
{
    if(pframe == NULL)
        return -1;   
    
    pframe->start = XYDM_FRAMR_START;
    pframe->sn = g_u8Count++;
    pframe->len = length + 5;
    pframe->type = type;
    pframe->code = code;
    pframe->context = buffer;
    pframe->crc = 0;
    pframe->stop = XYDM_FRAMR_STOP;
    
    return 0;
}


int xydm_frame_request(uint8_t type, uint8_t code, void *ctx)
{
    xy_frame_t frame;
    uint8_t *content = NULL;
    uint8_t len = 0;
    int tlen = 0;
    xydm_dtu_info_t *gpsinfo;
    xydm_ovoertop_t *overtop;
    uint8_t voertop_register;
    xydm_uplink_ctx_t *uplink;
    
    
    switch(type){
        case MSG_TYPE_PARAM_SET:
            break;
        case MSG_TYPE_STATUS_CHECK:
                if(code == MSG_CODE_CHECK_RSP_TEIMINAL_STATUS)
                    len = 20;
                else if(code == MSG_CODE_CHECK_REQ_OVERTOP_TIME)
                    len = 4;
                else if(code == MSG_CODE_CHECK_REQ_REGISTER_OVERTOP)
                    len = 1;
                else len = 0;           
            break;
        case MSG_TYPE_INTERACTION:
            if(code == MSG_CODE_INTERACTION_REQ_UPLINK){
                uplink = (xydm_uplink_ctx_t*)ctx;
                len = uplink->length + 8;//
            }
            break;
        case MSG_TYPE_EPHEMERIS:
            if(code == MSG_CODE_EPHEMERIS_REQ_INPUT){
                len = 23;
            }
            break;
        default:
            break;
    }
    
    if(len > 0){
        if(ctx == NULL)
            return -1;
        
        content = (uint8_t *)malloc(len);
        if(content == NULL)
            return -1;
        
        switch(type){
            case MSG_TYPE_STATUS_CHECK:
                if(code == MSG_CODE_CHECK_RSP_TEIMINAL_STATUS){
                    gpsinfo = (xydm_dtu_info_t*)ctx;
                    //get gps info todo
                    content[19] = gpsinfo->batterylvl;//todo batatery level 0-100
                    content[18] = (uint8_t)(gpsinfo->height.value >> 0);
                    content[17] = (uint8_t)(gpsinfo->height.value >> 8);
                    content[16] = (uint8_t)(gpsinfo->height.value >> 16);
                    content[15] = (uint8_t)(gpsinfo->height.value >> 24);
                
                    content[14] = (uint8_t)(gpsinfo->lati.value >> 0);
                    content[13] = (uint8_t)(gpsinfo->lati.value >> 8);
                    content[12] = (uint8_t)(gpsinfo->lati.value >> 16);
                    content[11] = (uint8_t)(gpsinfo->lati.value >> 24); 

                    content[10] = (uint8_t)(gpsinfo->lonti.value >> 0);
                    content[9] = (uint8_t)(gpsinfo->lonti.value >> 8);
                    content[8] = (uint8_t)(gpsinfo->lonti.value >> 16);
                    content[7] = (uint8_t)(gpsinfo->lonti.value >> 24); 
                    
                    content[0] = (uint8_t)(gpsinfo->date.year >> 8);
                    content[1] = (uint8_t)(gpsinfo->date.year >> 0);
                    content[2] = gpsinfo->date.month;
                    content[3] = gpsinfo->date.day;
                    content[4] = gpsinfo->time.hours;
                    content[5] = gpsinfo->time.minitues;
                    content[6] = gpsinfo->time.seconds;
                }else if(code == MSG_CODE_CHECK_REQ_OVERTOP_TIME){
                    overtop = (xydm_ovoertop_t*)ctx;
                    content[3] = (uint8_t)(overtop->sat_num >> 0);
                    content[2] = (uint8_t)(overtop->sat_num >> 8);
                    content[1] = (uint8_t)(overtop->est_time >> 0);
                    content[0] = (uint8_t)(overtop->est_time >> 8);
                }else if(code == MSG_CODE_CHECK_REQ_REGISTER_OVERTOP){
                    voertop_register = *(uint8_t *)ctx;
                    content[0] = voertop_register; //0x01:active, 0x02: register
                }            
                break;
            case MSG_TYPE_INTERACTION:
                if(code == MSG_CODE_INTERACTION_REQ_UPLINK){
                    uplink = (xydm_uplink_ctx_t*)ctx;
                    memcpy(content, uplink->number, 6);
                    content[6] = uplink->qos.value;
                    content[7] = uplink->length;
                    memcpy(&content[8],uplink->content, uplink->length);
                }
                break;
            case MSG_TYPE_EPHEMERIS:  //todo
                if(code == MSG_CODE_EPHEMERIS_REQ_INPUT){
                    //get gps xyz speed, xyz pos UTC ;
                }                
                break;
            default:
                break;
        }
    }
    
    xydm_frame_make(&frame, (len == 0)?NULL:content, len, type, code);

    tlen = xydm_frame_format(&frame, g_u8Txbuffer, sizeof(g_u8Txbuffer)); 
    free(content);    
    //printf("foramt frame len = %d.\r\n", tlen);
    if(tlen < 0)
        return -1;

    printf("Send:[ ");
    for(uint8_t indx = 0; indx < tlen; indx++){
        printf("%02x ", g_u8Txbuffer[indx]);
    }
    printf("]\r\n");
    int ret;
    for(uint8_t i=0;i < tlen;i++){
        ret = write(fd, &g_u8Txbuffer[i], 1);
        if(ret < 0){
            printf("write length error :%d[expect=1] fd=%d. \r\n",ret, fd);
            continue;
        } 
    }
/*     uint8_t blen = write(fd, g_u8Txbuffer, tlen);
    if(blen != tlen){
        printf("write length error :%d[expect=%d]\r\n",blen, tlen);
        return -1;
    } */
    
    return 0;
}

int xydm_frame_receive(uint8_t *rbuffer, uint8_t *rlen)
{
    struct pollfd rfds;
    uint8_t cnt;
    uint8_t len = 0;
    uint8_t curbyte = 0;
    uint8_t lastbyte = 0;
    
    int ret;
    
    cnt = 0;
    len = 0;
    do
    {
      if(cnt > 10)
          break;
      
      rfds.fd = fd;
      rfds.events = POLLIN;   
      rfds.revents = 0;   
      ret = poll(&rfds, 1, 100);
      if(ret == 0){
          cnt++;
          //printf("poll tmo \r\n");
          continue;
      }else if(ret < 0){
          cnt++;
          //printf("poll error \r\n");
          continue;              
      }else{
          if(rfds.revents != POLLIN){
            cnt++;
           // printf("not POLLIN events\r\n");
            continue;
          }
          cnt  = 0;
      }
#if 0    
	  char ch;
	   
      read(fd, &ch, 1);
      
      rbuffer[len++] = ch;
      lastbyte = curbyte;
      curbyte = ch;       
#else
	len = read(fd, rbuffer, 255);
	if (len <= 0){
		continue;
	}else{
		lastbyte = rbuffer[len - 2];
		curbyte = rbuffer[len - 1];
	}
	
#endif      

    }while ((lastbyte != 0x1A) || (curbyte != 0x1D));   
    
    printf("Recv:[ ");
    for(uint8_t indx = 0; indx < len; indx++){
        printf("%02x ", rbuffer[indx]);
    }
    printf("]\r\n");    
    if(len == 0){
        return -1;
    }
    
    *rlen = len;
    return 0;
}



int xydm_buffer2frame_parse(uint8_t *buff, uint8_t len, uint8_t *type, uint8_t *code, uint8_t *rlen, uint8_t *content)
{
    uint16_t crc;
    uint8_t crclen;
    uint8_t frmlen;
    uint8_t fcnt;
    uint8_t indx =0 ;
    int ret = -1;
    
    if(len < MINI_FRAME_SIZE){
        return -1;
    }
    for(indx =0; indx < len; indx++){
        if((buff[indx] != 0xaa) || (buff[indx + 1] != 0x11)){
            continue;
        }
        crclen = buff[indx + 4];
        frmlen  = crclen + 6;
        if(crclen < 5){
            //printf("crclen error %d \r\n", crclen);
            continue;
        }
        
        if((buff[indx + frmlen -1] != 0x1d) || (buff[indx + frmlen - 2] != 0x1a)){
            continue;
        }
  
        crc = crc16(&buff[indx + 2], crclen);
        if((((uint8_t)(crc >> 8)) != buff[indx + frmlen - 4]) || \
            ((uint8_t)(crc >> 0)) != buff[indx + frmlen - 3]){
            printf("crc error: %04x expect[%02x%02x] \r\n", crc, buff[indx + frmlen - 4], buff[indx + frmlen - 3]);
            continue;
        }

        *type = buff[indx + 5];
        *code = buff[indx + 6];
        fcnt = buff[indx + 2];
        if((rlen != NULL) && (content != NULL)){
            *rlen = crclen - 5;
            memcpy(content, &buff[indx + 7],crclen - 5);
        }
        ret = frmlen + indx;
        printf("frame:[");
        for(uint8_t i=0;i<frmlen;i++){
        	printf("%02x ",buff[indx+i]);
        }
        printf("] ");
        printf("fcnt = %02x, type =  %02x, code = %02x, len = %d. \r\n",fcnt, *type, *code, crclen - 5);
        break;
    }
    
    
    return ret;
}
int xydm_frame_parse(uint8_t *content, uint8_t *rlen, uint8_t *type, uint8_t *code)
{
    uint8_t len;
    uint8_t totallen;
    uint8_t lelftlen;
    uint8_t  u8type, u8code, u8rlen;
    uint8_t ctx[255];
    int ret = -1;
    uint8_t dolen = 0;
    
    if(0 > xydm_frame_receive(g_u8Rxbuffer, &len)){
        return -1;
    }    

    totallen = len;
    lelftlen = totallen;
    do{ 
        dolen = xydm_buffer2frame_parse(&g_u8Rxbuffer[totallen - lelftlen], lelftlen, &u8type, &u8code, &u8rlen, ctx);
        if(dolen < 0){
            printf("parse error .\r\n");
            break;
        }
        lelftlen = lelftlen - dolen;
        if((u8type == *type) && (u8code == *code)){
        	if((rlen != NULL) && (content != NULL)){
		    	*rlen = u8rlen;
		    	memcpy(content, ctx, u8rlen);
        	}
        	ret = 0;
        }
    }while(lelftlen > 0);
	
	memset(g_u8Rxbuffer, 0, sizeof(g_u8Rxbuffer));
	

    return ret;
}

int xydm_inquire_usrid(void)
{
    int ret = -1;
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_USER_NUMBER;
    uint8_t content[6];
    uint8_t len;
	uint8_t retry = 0;
	
    do{   
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_USER_NUMBER, NULL);
		if(ret < 0)
		    return -1;
        

		if(0 > xydm_frame_parse(content, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_USER_NUMBER){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_USER_NUMBER != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    
    if(code != MSG_CODE_CHECK_RSP_USER_NUMBER){
        return -1;
    }
    
    if(len != 6){
        return 1;
    }
 
    memcpy(g_u8Id, content, sizeof(g_u8Id)); 
     
    return 0;    

}


int xydm_inquire_swverison(void)
{
    int ret = -1;
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_SW_VERSION;
    uint8_t content[6];
    uint8_t len;
	uint8_t retry = 0;
	
    do{    
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_SW_VERSION, NULL);
		if(ret < 0)
		    return -1;
        

		if(0 > xydm_frame_parse(content, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_SW_VERSION){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_SW_VERSION != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    
    if(code != MSG_CODE_CHECK_RSP_SW_VERSION){
        return -1;
    }
    
    if(len != 1){
        return 1;
    }
    printf("moduel sw version: %02x \r\n", content[0]);
    
    return 0;    
}


int xydm_active_status_request(void)
{
    int ret = -1;
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_MODULE_ACTIVE;
    uint8_t content;
    uint8_t len;
 	uint8_t retry = 0;
 	
     do{   
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_MODULE_ACTIVE, NULL);
		if(ret < 0)
		    return -1;
    

		if(0 > xydm_frame_parse(&content, &len, &type,  &code)){
		    return -1;
		}
		if(code != MSG_CODE_CHECK_REQ_MODULE_ACTIVE){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_MODULE_ACTIVE != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    if(code != MSG_CODE_CHECK_RSP_MODULE_ACTIVE){
        return -1;
    }
    if(len != 1){
        return -1;
    }
    
    if(content != 0x01){
        return 1;
    }
    
    return 0;
}




int xydm_inquire_overtop_time(void)
{
    int ret = -1;
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_OVERTOP_TIME;
    xydm_ovoertop_t otop;
    uint8_t len;
    uint8_t rbuf[128];
    uint32_t u32start;
    uint32_t u32stop;
    uint8_t retry = 0;
    
    do{    
		otop.est_time = 24;
		otop.sat_num = 1;
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_OVERTOP_TIME, &otop);
		if(ret < 0)
		    return -1;
    

		if(0 > xydm_frame_parse(rbuf, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_OVERTOP_TIME){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_OVERTOP_TIME != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    if(code != MSG_CODE_CHECK_RSP_OVERTOP_TIME){
        return -1;
    }
    
    if(len == 0 || rbuf[0] == 0){
        return 1;
    }
    overtop_cnt = rbuf[0];
    memcpy(&next, &rbuf[1], sizeof(xydm_sat_ovtop_time_t));

	xydm_gps_time_get(&u32start, next.start.date.year,next.start.date.month,next.start.date.day,\
	next.start.time.hours,next.start.time.minitues,next.start.time.seconds); 
	
	xydm_gps_time_get(&u32stop, next.stop.date.year,next.stop.date.month,next.stop.date.day,\
	next.stop.time.hours,next.stop.time.minitues,next.stop.time.seconds); 
    
    printf("next overtop time start =%d ,stop =%d.\r\n",u32start, u32stop);
    return 0;    

}

int xydm_communication_request(void)
{
    int ret = -1;
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_COMMUNICATION;
    uint8_t content;
    uint8_t len;
 	uint8_t retry = 0;
 	
     do{   
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_COMMUNICATION, NULL);
		if(ret < 0)
		    return -1;
    

		if(0 > xydm_frame_parse(&content, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_COMMUNICATION){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_COMMUNICATION != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    if(code != MSG_CODE_CHECK_RSP_COMMUNICATION){
        return -1;
    }
    if(len != 1){
        return -1;
    }
    
    if(content != 0x01){
        return 1;
    }
    
    return 0;
}



int xydm_active_and_register(bool active)
{
    uint8_t type = MSG_TYPE_STATUS_CHECK;
    uint8_t code = MSG_CODE_CHECK_RSP_COMM_RESULT;

    uint8_t len;
    int ret = -1;
    uint8_t content = 0x01;
    uint8_t rbuf[2];
    uint8_t retry = 0;
    
    if(!active){
        content = 0x01;
    }
    else{
        content = 0x02;
    }
   
	do{
		ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_REQ_REGISTER_OVERTOP, &content);
		if(ret < 0)
		    return -1;
     

		if(0 > xydm_frame_parse(rbuf, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_COMM_RESULT){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_COMM_RESULT != code) && (retry < 5));
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    if(code != MSG_CODE_CHECK_RSP_COMM_RESULT){
        return -1;
    }
    if(len != 1){
        return -1;
    }
    
    if((rbuf[0] == 0x11) || (rbuf[0] == 0x21)){
        return 1;
    }
    
    return 0;
}

int xydm_responce_status(void)
{
    int ret = -1;
    xydm_dtu_info_t info;
    
    info.batterylvl = 0x64;
    
    if(gpssyned){
        info.height.fvalue = minmea_tocoord(&ggaframe.height);
        info.lati.fvalue = minmea_tocoord(&rmcframe.latitude);
        info.lonti.fvalue = minmea_tocoord(&rmcframe.longitude);
        info.date.year = rmcframe.date.year + 2000;
        info.date.month = rmcframe.date.month;
        info.date.day = rmcframe.date.day;
        info.time.hours = rmcframe.time.hours;
        info.time.minitues = rmcframe.time.minutes;
        info.time.seconds = rmcframe.time.seconds;
    }else{
        info.height.value = 0xFFFFFFFF;
        info.lati.value = 0xFFFFFFFF;
        info.lonti.value = 0xFFFFFFFF; 
        info.date.year = 0;
        info.date.month = 0;
        info.date.day = 0;
        info.time.hours = 0;
        info.time.minitues = 0;
        info.time.seconds = 0;        
    }
    
    ret = xydm_frame_request(MSG_TYPE_STATUS_CHECK, MSG_CODE_CHECK_RSP_TEIMINAL_STATUS, &info);
    if(ret < 0)
        return -1;
    
    
    return 0;    
}



int xydm_uplink_frame_request(void)
{
    int ret = -1;
    xydm_uplink_ctx_t ctx;
    uint8_t type = MSG_TYPE_INTERACTION;
    uint8_t code = MSG_CODE_CHECK_RSP_COMM_RESULT;
    uint8_t content;
    uint8_t len;
    uint8_t retry = 0;
    
    ctx.qos.qos.qos = 0;
    ctx.qos.qos.type = 1;
    ctx.length = 8;
    for(uint8_t indx = 0; indx < 8; indx++){
        ctx.content[indx] = indx+1;
    }
    memcpy(ctx.number, g_u8Id, sizeof(g_u8Id));
    
    do{
		ret = xydm_frame_request(MSG_TYPE_INTERACTION, MSG_CODE_INTERACTION_REQ_UPLINK, &ctx);
		if(ret < 0)
		    return -1;
    

		if(0 > xydm_frame_parse(&content, &len, &type,  &code)){
		    return -1;
		}
		
    	if(code != MSG_CODE_CHECK_RSP_COMM_RESULT){
			retry++;
		}
    }while((MSG_CODE_CHECK_RSP_COMM_RESULT != code) && (retry < 5));	
    
    if(type != MSG_TYPE_STATUS_CHECK){
        return -1;
    }
    
    if(code != MSG_CODE_CHECK_RSP_COMM_RESULT){
        return -1;
    }
    if(len != 1){
        return -1;
    }
    
    if(content == 0x01){
        return 0;
    }
    
    return 1;   
}




static uint16_t crc16(uint8_t* pData, int length)
{
    uint8_t i;
    uint16_t wCrc = 0xffff;
    while (length--) {
        wCrc ^= *(uint8_t *)pData++ << 8;
        for (i=0; i < 8; i++)
            wCrc = wCrc & 0x8000 ? (wCrc << 1) ^ 0x1021 : wCrc << 1;
    }
    return wCrc & 0xffff;
}


/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: xydm_daemon
 ****************************************************************************/

static int xydm_daemon(int argc, char *argv[])
{
    int ret = -1;
    int state = -1;
    /* Indicate that we are running */
    uint32_t waketime = 1000;/* ms */
	uint32_t starttime;
	uint32_t stoptime;
	uint32_t currtime;  
	  
    g_xydm_daemon_started = true;
    printf("xydm_daemon: Running\n");
    
    xydm_init();
    
    for (; ; )
    {
        if(state == -1){
        	xydm_module_wakeup();
        	usleep(10000*1000);
        	if(!gpssyned){
        		usleep(3000*1000);
        		continue;
        	}
			
			/* communication request */
			do{
				ret = xydm_communication_request();
				if(0 > ret){
					printf("requesst xydm module communication status failed.\r\n");
					usleep(2000*1000);
				}else if(ret > 0){ // need active
					printf("no downlink broadcast signals.\r\n");
					usleep(2000*1000);
				}else{
					printf("recved downlink broadcast signals.\r\n");			
				}	
			}while(ret != 0);
			
			/* inquire module active status */
			printf("xydm module doing status inquire.\r\n");
			ret = xydm_active_status_request();
			if(0 > ret){
				printf("inquire xydm module status failed.\r\n");
				usleep(3000*1000);
				continue;
			}else if(ret > 0){ // need active
				do{
					printf("xydm module doing activite.\r\n");
					ret = xydm_active_and_register(false);
					if(0 > ret){
						printf("register xydm module activite failed.\r\n");
						usleep(2000*1000);
					}else if(ret > 0){ // need active
						printf("xydm module is inactive.\r\n");
						usleep(2000*1000);
					}else{
						printf("xydm module is activited.\r\n");			
					}					
				}while(ret != 0);
				printf("xydm module activited successfully.\r\n");
			}else{
				printf("xydm module is active.\r\n");			
			}

			/* overtop register */			
			do{
				printf("xydm module doing over-top register.\r\n");
				ret = xydm_active_and_register(true);
				if(0 > ret){
					printf("register xydm module overtop failed.\r\n");
					usleep(2000*1000);
				}else if(ret > 0){ // need active
					printf("xydm module is not registered.\r\n");
					usleep(2000*1000);
				}else{
					printf("xydm module is registered.\r\n");			
				}
			}while(ret != 0);
			state = 0;
			waketime = 1000;
#if 0            
//            printf("inquire over-top time.\r\n");
//            if(0 == xydm_inquire_overtop_time())
            {
            	
            	xydm_gps_time_get(&starttime, next.start.date.year,next.start.date.month,next.start.date.day,\
            	next.start.time.hours,next.start.time.minitues,next.start.time.seconds); 
            	
            	xydm_gps_time_get(&stoptime, next.stop.date.year,next.stop.date.month,next.stop.date.day,\
            	next.stop.time.hours,next.stop.time.minitues,next.stop.time.seconds); 
            	
            	xydm_gps_time_get(&currtime, rmcframe.date.year, rmcframe.date.month, rmcframe.date.day,\
            	rmcframe.time.hours, rmcframe.time.minutes, rmcframe.time.seconds);             	
            	
            	waketime = (starttime - currtime);
                xydm_module_sleep();
                usleep(waketime);
                
                xydm_module_wakeup();
                waketime = 1000;
                //state = 0;
                state = -1;
            }
#endif            
        }if(state == 0){
 			/* communication request */
			do{
				ret = xydm_communication_request();
				if(0 > ret){
					printf("requesst xydm module communication status failed.\r\n");
					usleep(2000*1000);
				}else if(ret > 0){ // need active
					printf("no downlink broadcast signals.\r\n");
					usleep(2000*1000);
				}else{
					printf("recved downlink broadcast signals.\r\n");			
				}	
			}while(ret != 0);
			
 			/* uplink request */
			do{
				ret = xydm_uplink_frame_request();
				if(0 > ret){
					printf("xydm module uplink frame send error.\r\n");
					usleep(2000*1000);
				}else if(ret > 0){ // need active
					printf("xydm module uplink frame send failed.\r\n");
					usleep(2000*1000);
				}else{
					printf("xydm module uplink frame send ok.\r\n");			
				}	
			}while(ret != 0);			

			if(uplink_cnt++%5 == 0)
				state = 1;
        }if(state == 1){
        	waketime  = 1000;
        	xydm_gps_time_get(&currtime, rmcframe.date.year, rmcframe.date.month, rmcframe.date.day,\
            	rmcframe.time.hours, rmcframe.time.minutes, rmcframe.time.seconds); 
            if(currtime <= stoptime){
            	state = -1;
            }else {
            
		    }
        }
        usleep(waketime*1000);
    }

  g_xydm_daemon_started = false;

  printf("xydm_daemon: Terminating\n");
  return EXIT_FAILURE;
}

static int gps_daemon(int argc, char *argv[])
{  
  int gfd;
  int cnt;
  char ch;
  char line[MINMEA_MAX_LENGTH];
  uint32_t ublox_utc;

  struct pollfd rfds;
  int ret;
  /* Open the GPS serial port */

  gfd = open("/dev/ttyS1", O_RDONLY | O_NONBLOCK);
  if (gfd < 0)
    {
      printf("Unable to open file /dev/ttyS1\n");
    }

  /* Run forever */
  rfds.fd = gfd;
  rfds.events = POLLIN;
  for (; ; )
    {
      /* Read until we complete a line */

      cnt = 0;
      do
        {
          ret = poll(&rfds, 1, 1000);
          if(ret == 0){
              printf("poll tmo \r\n");
              continue;
          }else if(ret < 0){
              printf("poll error \r\n");
              continue;              
          }else{
              if(rfds.revents != POLLIN){
                printf("not POLLIN events\r\n");
                continue;
              }
          }
          read(gfd, &ch, 1);
          if (ch != '\r' && ch != '\n')
            {
              line[cnt++] = ch;
            }
        }
      while (ch != '\r' && ch != '\n');

      line[cnt] = '\0';

      switch (minmea_sentence_id(line, false))
        {
          case MINMEA_SENTENCE_RMC:
            {
              if (minmea_parse_rmc(&rmcframe, line))
                {
                  gpssyned = true;  
                  gpslocated = true;
                  printf("Floating point degree latitude.: %2.6f\n",
                         minmea_tocoord(&rmcframe.latitude));
                  printf("Floating point degree longitude: %2.6f\n",
                         minmea_tocoord(&rmcframe.longitude));
                  printf("GPS UTC date...................: %d-%02d-%02d\n",
                         2000 + rmcframe.date.year, rmcframe.date.month, rmcframe.date.day); 
                         
                  printf("GPS UTC time...................: %02d:%02d:%02d\n",
                         rmcframe.time.hours, rmcframe.time.minutes, rmcframe.time.seconds);   
                  
                  xydm_gps_time_get(&ublox_utc, rmcframe.date.year, rmcframe.date.month, rmcframe.date.day,\
            		rmcframe.time.hours, rmcframe.time.minutes, rmcframe.time.seconds);  
            		 
                  printf("GPS UTC time in Seconds........: %d\n", ublox_utc);              		                            
                }
              else
                {
                    printf("$xxRMC sentence is not parsed\n");
                }
            }
            break;

          case MINMEA_SENTENCE_GGA:
            {

              if (minmea_parse_gga(&ggaframe, line))
                {  
                  printf("Floating point meters height...: %2.6f\n",
                         minmea_tocoord(&ggaframe.height));
                         
                  printf("Tracked satellites.............: %d\n",
                         ggaframe.satellites_tracked);     
                }
              else
                {
                  printf("$xxGGA sentence is not parsed\n");
                }
            }
            break;

          case MINMEA_INVALID:
          case MINMEA_UNKNOWN:
          case MINMEA_SENTENCE_GSA:
          case MINMEA_SENTENCE_GLL:
          case MINMEA_SENTENCE_GST:
          case MINMEA_SENTENCE_GSV:
            {
            }
            break;
        }
        usleep(10*1000);
    }

  printf("gps_daemon: Terminating\n");
  return EXIT_FAILURE;
}
/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * xydm_main
 ****************************************************************************/

int main(int argc, FAR char *argv[])
{
    int ret;

    printf("xydm_main: Starting the xydm_daemon\n");
    if (g_xydm_daemon_started)
    {
      printf("xydm_main: xydm_daemon already running\n");
      return EXIT_SUCCESS;
    }
    
    ret = task_create("xydm_daemon", CONFIG_EXAMPLES_XYDM_PRIORITY,
                    CONFIG_EXAMPLES_XYDM_STACKSIZE, xydm_daemon,
                    NULL);
    if (ret < 0)
    {
      int errcode = errno;
      printf("xydm_main: ERROR: Failed to start xydm_daemon: %d\n",
             errcode);
      return EXIT_FAILURE;
    }

    ret = task_create("gps_daemon", CONFIG_EXAMPLES_GPS_PRIORITY,
                    CONFIG_EXAMPLES_GPS_STACKSIZE, gps_daemon,
                   NULL);
    if (ret < 0)
    {
      int errcode = errno;
      printf("xydm_main: ERROR: Failed to start gsp_daemon: %d\n",
             errcode);
      return EXIT_FAILURE;
    }

    printf("xydm_main: xydm_daemon started\n");
    return EXIT_SUCCESS;
}




